﻿using System;
using System.Collections.Generic;
using System.Text;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using Xeno.Core;
using OpenTK.Math;
namespace Xeno.Module
{
    public class MeshRenderer : XenoModule
    {

        public XenoMaterial Material { get; set; }
        public bool Sync { get; private set; }
        private float[] Vertices;
        private float[] Normals;
        private float[] Coords;
        private int[] Indices;
        private int List = 0;

        public MeshRenderer()
        {
        
            Name = "Mesh Renderer";
            ModuleAuthor = "Antony Wells";
            ModuleCopyright = "(c)Double Think Games 2009/10";
            ResetMeshRenderer();
        
        }
        
        public void ResetMeshRenderer()
        {

            Sync = true;

        }

        public override void DoUpdate()
        {
            
            
        }
        private void RenderVertex(XenoVertex vertex)
        {
            GL.TexCoord3(vertex.Tex0);
            GL.Normal3(vertex.Normal);
            GL.Color4(vertex.Color);
            GL.Vertex3(vertex.Position);
        }
        public override void DoRender()
        {
            GL.PushAttrib(AttribMask.AllAttribBits);
            XenoMesh msh = Attached.Mesh;

            XenoDebug.AssertNull(msh, "XenoMod_MeshRenderer.DoRender");


            GL.Enable(EnableCap.Blend);
            GL.Disable(EnableCap.AlphaTest);
            GL.Disable(EnableCap.ScissorTest);
            GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);

            GL.MatrixMode(MatrixMode.Projection);
            Matrix4 projectionMatrix = XenoCore.CurrentView.Camera.Projection;
            GL.LoadMatrix(ref projectionMatrix);

            GL.MatrixMode(MatrixMode.Modelview);
            Matrix4 worldMatrix = Attached.WorldMatrix * XenoCore.CurrentView.WorldMatrix;
            GL.LoadMatrix(ref worldMatrix);



            if (Sync)
            {
                Sync = false;
                int index = 0;
                Vertices = new float[msh.Vertices.Count * 3];
                Normals = new float[msh.Vertices.Count * 3];
                Coords = new float[msh.Vertices.Count * 3];
                foreach (XenoVertex v in msh.Vertices)
                {

                    float[] verts = Vertices;
                    verts[index] = v.Position.X;
                    verts[index + 1] = v.Position.Y;
                    verts[index + 2] = v.Position.Z;

                    Normals[index] = v.Normal.X;
                    Normals[index + 1] = v.Normal.Y;
                    Normals[index + 2] = v.Normal.Z;

                    Coords[index] = v.Tex0.X;
                    Coords[index + 1] = v.Tex0.Y;
                    Coords[index + 2] = v.Tex0.Z;

                    index += 3;
                    List = 0;
                }

                Indices = new int[msh.Triangles.Count * 3];
                index = 0;
                foreach (XenoTriangle t in msh.Triangles)
                {
                    Indices[index] = t.V1;
                    Indices[index + 1] = t.V2;
                    Indices[index + 2] = t.V3;
                    index += 3;
                }

            }



            GL.EnableClientState(EnableCap.VertexArray);
            GL.EnableClientState(EnableCap.TextureCoordArray);
            GL.EnableClientState(EnableCap.NormalArray);

            GL.VertexPointer<float>(3, VertexPointerType.Float, 0, Vertices);
            GL.NormalPointer<float>(NormalPointerType.Float, 0, Normals);
            GL.TexCoordPointer<float>(3, TexCoordPointerType.Float, 0, Coords);


            var first = true;


            GL.DepthMask(true);
            GL.DepthFunc(DepthFunction.Lequal);
            DrawMesh();
            GL.DepthFunc(DepthFunction.Equal);
            //GL.DepthMask(false);

            foreach (var light in XenoCore.LightList)
            {


                XenoCore.CurrentLight = light;

                Material.Bind();

                DrawMesh();

                Material.Unbind();
                if (first)
                {
                    GL.BlendFunc(BlendingFactorSrc.One, BlendingFactorDest.One);
                    first = false;
                }
            }


            GL.DisableClientState(EnableCap.VertexArray);
            GL.DisableClientState(EnableCap.NormalArray);
            GL.DisableClientState(EnableCap.TextureCoordArray);

            GL.DepthFunc(DepthFunction.Lequal);

            GL.Disable(EnableCap.Blend);

            DrawBounds(msh.BoundingBox);

            GL.PopAttrib();

        }
        public static void DrawBounds(Vector3[] bb)
        {
            GL.Color4(System.Drawing.Color.White);

            GL.LineWidth(4);

            GL.Begin(BeginMode.Lines);

            GL.Vertex3(bb[0]);
            GL.Vertex3(new Vector3(bb[1].X, bb[0].Y, bb[0].Z));

            GL.Vertex3(bb[0]);
            GL.Vertex3(new Vector3(bb[0].X,bb[1].Y,bb[0].Z));

            GL.Vertex3(bb[0]);
            GL.Vertex3(new Vector3(bb[0].X, bb[0].Y, bb[1].Z));


            GL.End();
        }
        private void DrawMesh()
        {
            GL.DrawElements<int>(BeginMode.Triangles, Indices.Length, DrawElementsType.UnsignedInt, Indices);

        }

    }
}
